﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Workflows.Components.Entities.Properties;

namespace Workflows.Components.Entities.Providers
{
    [Serializable]
    public class SamplingComponent:WorkflowComponentBase
    {
        #region props

        private SamplingInstruction _Instruction;
        public override InstructionBase Instruction
        {
            get { return _Instruction; }
            set { _Instruction = (SamplingInstruction)value; }
        }

        private SamplingOutput _Output;
        public override ResultBase Output
        {
            get { return _Output; }
            set { _Output = (SamplingOutput)value; }
        }

        /// <summary></summary>
        public string EntityProviderFilePath
        {
            get
            {
                return this._Instruction.EntityProviderFilePath;
            }
            set
            {
                this._Instruction.EntityProviderFilePath = value;
            }
        }

        /// <summary></summary>
        public DataProviderType DbProvider
        {
            get
            {
                return this._Instruction.DbProvider;
            }
            set
            {
                this._Instruction.DbProvider = value;
            }
        }

        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._Instruction.ConnStr;
            }
            set
            {
                this._Instruction.ConnStr = value;
            }
        }

        /// <summary></summary>
        public string SelectSql
        {
            get
            {
                return this._Instruction.SelectSql;
            }
            set
            {
                this._Instruction.SelectSql = value;
            }
        }

        /// <summary></summary>
        public string IDAttributeName
        {
            get
            {
                return this._Instruction.IDAttributeName;
            }
            set
            {
                this._Instruction.IDAttributeName = value;
            }
        }

        /// <summary>
        /// when seed attribute is available, it sample soruce data using seed value
        /// randomly select a seed value from sorted seed values
        /// </summary>
        public string SeedAttributeName
        {
            get
            {
                return this._Instruction.SeedAttributeName;
            }
            set
            {
                this._Instruction.SeedAttributeName = value;
            }
        }

        /// <summary></summary>
        public SamplingMethod Method
        {
            get
            {
                return this._Instruction.Method;
            }
            set
            {
                this._Instruction.Method = value;
            }
        }

        /// <summary></summary>
        public int SampleSize
        {
            get
            {
                return this._Instruction.SampleSize;
            }
            set
            {
                this._Instruction.SampleSize = value;
            }
        }

        /// <summary></summary>
        public Dictionary<string, string> Filters
        {
            get
            {
                return this._Instruction.Filters;
            }
            set
            {
                this._Instruction.Filters = value;
            }
        }

        /// <summary></summary>
        public Dictionary<string, Range<int>> RangeFilters
        {
            get
            {
                return this._Instruction.RangeFilters;
            }
            set
            {
                this._Instruction.RangeFilters = value;
            }
        }

        /// <summary></summary>
        public string SamplingResultFilePath
        {
            get
            {
                return this._Instruction.SamplingResultFilePath;
            }
            set
            {
                this._Instruction.SamplingResultFilePath = value;
            }
        }

        #endregion

        public SamplingComponent():base()
        {
            this.ComponentActivityType = WorkflowActivityType.SimpleActivity;
            this.ComponentCategory = WorkflowComponentCategory.Entity_Relations.ToString();
            this.ComponentName = "Sampling";
            this.Description = "Randomly take a sample of specified size from source entities";
            this.ComponentIcon = Resources.apds_206;
            this.ComponentImage = Resources.tour;

            this._Instruction = new SamplingInstruction(
                this.ComponentID, Guid.Empty,
                string.Empty, DataProviderType.MSSQL, 
                string.Empty, string.Empty, string.Empty,string.Empty,
                SamplingMethod.Count, 100,
                new Dictionary<string, string>(), new Dictionary<string, Range<int>>(),
                string.Empty);

            this._Output = new SamplingOutput(this.ComponentID, Guid.Empty, 0, string.Empty);
        }

        public override WorkflowComponentBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                SamplingComponent component = base.Instantiate(xNode) as SamplingComponent;

                component.EntityProviderFilePath = XmlDataUtil.GetAttributeValue(xNode, "EntityProviderFilePath", "");
                component.DbProvider = (DataProviderType)int.Parse(
                                                                XmlDataUtil.GetAttributeValue(xNode, "DbProvider",
                                                                                              ((int)
                                                                                               DataProviderType.MSSQL).
                                                                                                  ToString()));
                component.ConnStr = XmlDataUtil.GetAttributeValue(xNode, "ConnStr", "");
                component.SelectSql = XmlDataUtil.GetAttributeValue(xNode, "SelectSql", "");
                component.IDAttributeName = XmlDataUtil.GetAttributeValue(xNode, "IDAttributeName", "");
                component.SeedAttributeName = XmlDataUtil.GetAttributeValue(xNode, "SeedAttributeName", "");
                component.Method =
                    (SamplingMethod)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "Method", ((int)SamplingMethod.Count).ToString()));
                component.SampleSize = int.Parse(XmlDataUtil.GetAttributeValue(xNode, "Size", "100"));
                component.SamplingResultFilePath = XmlDataUtil.GetAttributeValue(xNode, "ResultFilePath", "");

                XmlNodeList filterNodes = xNode.SelectNodes("Filters/Filter");
                if (filterNodes != null && filterNodes.Count > 0)
                {
                    component.Filters = new Dictionary<string, string>();
                    foreach (XmlNode filterNode in filterNodes)
                    {
                        string attrName = XmlDataUtil.GetAttributeValue(filterNode, "AttributeName", "");
                        string attrValue = XmlDataUtil.GetAttributeValue(filterNode, "AttributeValue", "");
                        component.Filters.Add(attrName, attrValue);
                    }
                }

                XmlNodeList rangeFilterNodes = xNode.SelectNodes("RangeFilters/RangeFilter");
                if (rangeFilterNodes != null && rangeFilterNodes.Count > 0)
                {
                    component.RangeFilters = new Dictionary<string, Range<int>>();
                    foreach (XmlNode rangeNode in rangeFilterNodes)
                    {
                        string attrName = XmlDataUtil.GetAttributeValue(rangeNode, "AttributeName", "");
                        Range<int> range = new Range<int>();
                        range.FromValue = int.Parse(XmlDataUtil.GetAttributeValue(rangeNode, "From", "0"));
                        range.ToValue = int.Parse(XmlDataUtil.GetAttributeValue(rangeNode, "To", "100"));
                        component.RangeFilters.Add(attrName, range);

                    }
                }

                return component;
            }
            else
            {
                throw new Exception("Unable to instantiate email: invalid type specified in xml node");
            }
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = base.Serialize(ref xDoc, ref parentNode);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "EntityProviderFilePath", this.EntityProviderFilePath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DbProvider", ((int)this.DbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnStr", this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SelectSql", this.SelectSql);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "IDAttributeName", this.IDAttributeName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SeedAttributeName", "");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Method", ((int)this.Method).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Size", this.SampleSize.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ResultFilePath", this.SamplingResultFilePath);

            if (this.Filters != null && this.Filters.Count > 0)
            {
                XmlNode filterRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Filters");
                foreach (string attrName in this.Filters.Keys)
                {
                    XmlNode filterNode = XmlDataUtil.AddElement(ref xDoc, filterRootNode, "Filter");
                    XmlDataUtil.UpdateAttribute(ref xDoc, filterNode, "AttributeName", attrName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, filterNode, "AttributeValue", this.Filters[attrName]);
                }
            }

            if (this.RangeFilters != null && this.RangeFilters.Count > 0)
            {
                XmlNode rangeRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "RangeFilters");
                foreach (string attrName in this.RangeFilters.Keys)
                {
                    XmlNode rangeNode = XmlDataUtil.AddElement(ref xDoc, rangeRootNode, "RangeFilter");
                    XmlDataUtil.UpdateAttribute(ref xDoc, rangeNode, "AttributeName", attrName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, rangeNode, "From",
                                                this.RangeFilters[attrName].FromValue.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, rangeNode, "To",
                                                this.RangeFilters[attrName].ToValue.ToString());
                }
            }

            return xNode;
        }
    }
}
